﻿using anydata.Entitys;
using MongoDB.Driver;
using Newtonsoft.Json.Linq;

namespace anydata.Services;

public class AssignTaskService : ITransient, IPostInsert, IPostReplace, IPostSetFields
{
    private const string InstanceColl = "work-instance";
    private const string AssignTaskColl = "assign-task";
    private const string PublicAssignTaskColl = "-" + AssignTaskColl;
    private readonly DataProvider _provider;

    public AssignTaskService(DataProvider provider)
    {
        _provider = provider;
    }

    async Task IPostInsert.Invoke(TokenModel token, string collectName, List<EntityBase> list)
    {
        if (collectName != InstanceColl) return;
        foreach (var item in list)
        {
            await Execute(token, item, item.status);
        }
    }

    async Task IPostReplace.Invoke(TokenModel token, string collectName, List<EntityBase> list)
    {
        if (collectName != InstanceColl) return;
        foreach (var item in list)
        {
            await Execute(token, item, item.status);
        }
    }

    async Task IPostSetFields.Invoke(TokenModel token, string collectName, CollectSetFields data)
    {
        if (collectName != InstanceColl) return;

        var instanceStatus = data.Update.SelectToken("_set_.status");
        if (instanceStatus is not null && instanceStatus.Type == JTokenType.Integer)
        {
            await ExecuteByInstanceId(token, data.Id, instanceStatus.Value<int>());
        }
    }

    async Task ExecuteByInstanceId(TokenModel token, string id, int status)
    {
        var result = _provider.TryGetCollection<EntityBase>(token, DataProvider.InstanceCollName);
        if (!result.success)
        {
            Console.WriteLine("获取流程实例集合失败！");
            return;
        }

        var instanceObj = await result.data.Find(i => i.id == id).FirstOrDefaultAsync();
        await Execute(token, instanceObj, status);
    }

    async Task Execute(TokenModel token, EntityBase instanceObj, int status)
    {
        var instance = new XWorkInstance(instanceObj);
        if (instance.InstanceData is not null)
        {
            var assignTask = instance.InstanceData.assignTask;
            if (assignTask is null)
            {
                return;
            }

            // 判断当前空间是不是发起单位
            var isMySpace = !string.IsNullOrEmpty(instance.applyId) && instance.belongId == instance.applyId;

            if (status < 100)
            {
                Console.WriteLine("任务提交");
                await Submit(token, assignTask, instance, isMySpace);
            }
            else if (status >= 200)
            {
                Console.WriteLine("任务驳回");
                await Reject(token, assignTask, isMySpace);
            }
            else
            {
                Console.WriteLine("任务通过");
                var result = _provider.TryGetCollection<XTempData>(token, DataProvider.TempDataCollName);
                var things = await instance.InstanceData.GetThings(result.data);
                await Approve(token, assignTask, things, isMySpace, instance);
            }
        }
    }

    async Task Submit(TokenModel token, EntityBase assignTask, XWorkInstance instance, bool isMySpace)
    {
        var coll = _provider.TryGetCollection<EntityBase>(token, PublicAssignTaskColl);
        if (!coll.success) return;

        try
        {
            var update = Builders<EntityBase>.Update
                .Set("instanceId", instance.id)
                .Set("isReject", false)
                .Set("taskStatus", "submitted");
            var assign = await coll.data.FindOneAndUpdateAsync(x => x.id == assignTask.id, update, new()
            {
                ReturnDocument = ReturnDocument.After,
            });
            if (isMySpace)
            {
                var myColl = _provider.TryGetCollection<EntityBase>(token, AssignTaskColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == assignTask.id, assign);
            }
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务失败：" + error);
        }
    }

    async Task Reject(TokenModel token, EntityBase assignTask, bool isMySpace)
    {
        var coll = _provider.TryGetCollection<EntityBase>(token, PublicAssignTaskColl);
        if (!coll.success) return;
        try
        {
            var update = Builders<EntityBase>.Update
                .Set("isReject", true)
                .Set("taskStatus", "rejected");
            var assign = await coll.data.FindOneAndUpdateAsync(x => x.id == assignTask.id, update, new()
            {
                ReturnDocument = ReturnDocument.After
            });
            if (isMySpace)
            {
                var myColl = _provider.TryGetCollection<EntityBase>(token, AssignTaskColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == assignTask.id, assign);
            }
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务失败：" + error);
        }
    }

    async Task Approve(TokenModel token, EntityBase assignTask, Dictionary<string, List<EntityBase>> thingMap,
        bool isMySpace, XWorkInstance instance)
    {
        var coll = _provider.TryGetCollection<EntityBase>(token, PublicAssignTaskColl);
        if (!coll.success) return;
        try
        {
            var thingId = thingMap.ToDictionary(t => t.Key, t => t.Value.Select(x => x.id).ToList());
            var update = Builders<EntityBase>.Update
                .Set("thingId", thingId)
                .Set("isReject", false)
                .Set("taskStatus", "finished")
                .Unset("previousInstanceId");
            var assign = await coll.data.FindOneAndUpdateAsync(x => x.id == assignTask.id, update, new()
            {
                ReturnDocument = ReturnDocument.After
            });
            if (isMySpace)
            {
                var myColl = _provider.TryGetCollection<EntityBase>(token, AssignTaskColl);
                if (!myColl.success) return;

                await myColl.data.ReplaceOneAsync(x => x.id == assignTask.id, assign);
            }

            // 数据处理
            if ("step".Equals(assignTask.extensions["assignType"]) && !assignTask.extensions.ContainsKey("modelId"))
            {
                foreach (var (formId, things) in thingMap)
                {
                    var collName = instance.InstanceData?.FormCollectionNameMap[formId];
                    if (collName == null) return;
                    
                    var publicThingColl = _provider.TryGetCollection<EntityBase>(token, '-' + collName);
                    if (!publicThingColl.success) return;

                    var thingColl = _provider.TryGetCollection<EntityBase>(token, collName);
                    if (!thingColl.success) return;
                    
                    var asyncCursor = await publicThingColl.data.FindAsync(x =>
                        x.extensions["period"] == assignTask.extensions["period"] &&
                        x.extensions["treeId"] == assignTask.extensions["treeId"]);
                    
                    var publicThings = await asyncCursor.ToListAsync();
                    if (publicThings == null || publicThings.Count == 0) return;
                    
                    foreach (var publicThing in publicThings)
                    {
                        await thingColl.data.ReplaceOneAsync(x => x.id == publicThing.id, publicThing);
                    }
                }
            }
        }
        catch (Exception error)
        {
            Console.WriteLine("更新任务失败：" + error);
        }
    }
}